#include "sc/xml.h"

#include "libxml/parser.h"
#include "libxml/xmlmemory.h"
#include "libxml/relaxng.h"

using namespace xml;

// SCC Element
const xmlChar* scc::_context         = (const xmlChar*) "sc-context";
const xmlChar* scc::_file            = (const xmlChar*) "file";
const xmlChar* scc::_xslt            = (const xmlChar*) "xslt";
const xmlChar* scc::_mmi             = (const xmlChar*) "mmi";
const xmlChar* scc::_element_label   = (const xmlChar*) "element-label";
const xmlChar* scc::_attribute_label = (const xmlChar*) "attribute-label";

// SCC Attributes
const xmlChar* scc::_title           = (const xmlChar*) "title";
const xmlChar* scc::_setup           = (const xmlChar*) "setup";
const xmlChar* scc::_rng             = (const xmlChar*) "rng";
const xmlChar* scc::_xsl             = (const xmlChar*) "xsl";
const xmlChar* scc::_xsltres         = (const xmlChar*) "xsltres";
const xmlChar* scc::_path            = (const xmlChar*) "path";
const xmlChar* scc::_for             = (const xmlChar*) "for";
const xmlChar* scc::_value           = (const xmlChar*) "value";
const xmlChar* scc::_default         = (const xmlChar*) "default";
const xmlChar* scc::_icon            = (const xmlChar*) "icon";
const xmlChar* scc::_error           = (const xmlChar*) "error";
const xmlChar* scc::_help            = (const xmlChar*) "help";
const xmlChar* scc::_type            = (const xmlChar*) "type";
const xmlChar* scc::_type_directory  = (const xmlChar*) "directory";
const xmlChar* scc::_type_file       = (const xmlChar*) "file";

/**
* Do a XSL transformation
*
* @param sXmlFile XML file name
* @param sXslFile XSL file name
* @param sXsltResFile XSL transformation result file name
*
* @return true if transformation was succesfull
*/
bool xml::XslTransform(const wxString& sXmlFile, const wxString& sXslFile, const wxString& sXslResFile)
{
	bool bXslt = false;
	xsltStylesheetPtr xslt = xsltParseStylesheetFile( (const xmlChar*) sXslFile.utf8_str().data() );
	if (xslt)
	{
		xmlDocPtr doc = xmlParseFile( sXmlFile.utf8_str() );
		if (doc)
		{
			xmlDocPtr res = xsltApplyStylesheet(xslt, doc, NULL);
			xsltSaveResultToFilename(sXslResFile.utf8_str(), res, xslt, 0);
			xmlFreeDoc(res);
			bXslt = true;
		}
		xsltFreeStylesheet(xslt);
	}
	return bXslt;
}

bool xml::RngValidate(const wxString& sXmlFile, const wxString& sRngFile)
{
	bool bValid = false;
	xmlDocPtr xmlDoc = xmlReadFile(sXmlFile.utf8_str(), NULL, 0);
	if (xmlDoc)
	{
		xmlRelaxNGParserCtxtPtr rngCtx = xmlRelaxNGNewParserCtxt(sRngFile.utf8_str());
		xmlRelaxNGPtr schema = xmlRelaxNGParse(rngCtx);
		if (schema)
		{
			xmlRelaxNGValidCtxtPtr rngValidCtx = xmlRelaxNGNewValidCtxt(schema);
			if (rngValidCtx)
			{
				bValid = (0 == xmlRelaxNGValidateDoc(rngValidCtx, xmlDoc));
				xmlRelaxNGFreeValidCtxt(rngValidCtx);
			}
			xmlRelaxNGFree(schema);
		}
		xmlRelaxNGFreeParserCtxt(rngCtx);
		xmlFreeDoc(xmlDoc);
	}
	return bValid;
}

bool xml::RngValidate(const xmlDocPtr xmlDoc, const xmlNodePtr xmlElement, const wxString& sRngFile)
{
	bool bValid = false;
	xmlRelaxNGParserCtxtPtr rngCtx = xmlRelaxNGNewParserCtxt(sRngFile.utf8_str());
	xmlRelaxNGPtr schema = xmlRelaxNGParse(rngCtx);
	if (schema)
	{
		xmlRelaxNGValidCtxtPtr rngValidCtx = xmlRelaxNGNewValidCtxt(schema);
		if (rngValidCtx)
		{
			bValid = (0 == xmlRelaxNGValidateFullElement(rngValidCtx, xmlDoc, xmlElement));
			xmlRelaxNGFreeValidCtxt(rngValidCtx);
		}
		xmlRelaxNGFree(schema);
	}
	xmlRelaxNGFreeParserCtxt(rngCtx);
	return bValid;
}
